﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

namespace Rifts.Models.Definitions
{
	public class Catalog
	{
		readonly List<Race> m_Races = new List<Race>();
		readonly List<CharacterClass> m_Classes = new List<CharacterClass>();
		readonly SkillDefinitionCollection m_Skills = new SkillDefinitionCollection();
		readonly XElement m_SecondarySkillsDefinition;

		public Catalog()
		{
			//TODO: Make the loading customizable

			var dataPath = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Data"));

			var books = new List<XElement>();

			foreach (var file in dataPath.GetFiles("*.rifts-book"))
			{
				var book = XElement.Load(file.FullName);
				books.Add(book);

				foreach (var racialGroup in book.Elements("RacialGroup"))
					foreach (var race in racialGroup.Elements("Race"))
						m_Races.Add(new Race(book, racialGroup, race, this));

				foreach(var item in book.Elements("Class"))
					m_Classes.Add(new CharacterClass(book, item, this));

				//handle actual skills
				if (book.Element("Skills") != null)
				{
					foreach (var group in book.Element("Skills").Elements("SkillGroup"))
					{
						var groupName = group.GetAttribute("Name");
						foreach (var skill in group.Elements("Skill"))
						{
							m_Skills.Add(new SkillDefinition(this, book, groupName, skill));
						}
					}
				}


				//TODO: Is there a way to support merging?
				var secondary = book.Element("SecondarySkills");
				if (secondary != null)
					m_SecondarySkillsDefinition = secondary;
			}


			//resolve skill references in groups
			foreach (var book in books)
			{
				//resolve skill references
				if (book.Element("Skills") != null)
				{
					foreach (var group in book.Element("Skills").Elements("SkillGroup"))
					{
						var bookName = book.GetAttribute("Name");
						var groupName = group.GetAttribute("Name");
						foreach (var skill in group.Elements("SkillRef"))
						{
							var skillEntry = m_Skills.FindByName(skill.GetAttribute("Name"));
							if (skillEntry == null)
								throw new Exception(String.Format("Cannot find skill named '{0}' for skill group '{1}' in file {2}", skill.GetAttribute("Name"), groupName, bookName));
							else
								m_Skills.Add(new SkillDefinition(this, groupName, skillEntry));
						}
					}
				}
			}

			//resolve skill references in subskills
			foreach (var skill in m_Skills)
			{
				skill.ResolvedFreeSkills(this);
			}





		}

		public List<CharacterClass> Classes
		{
			get { return m_Classes; }
		}

		public List<Race> Races
		{
			get { return m_Races; }
		}

		public XElement SecondarySkillsDefinition
		{
			get { return m_SecondarySkillsDefinition; }
		}

		public SkillDefinitionCollection Skills
		{
			get { return m_Skills; }
		}



	}
}